﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Xml.Serialization;
using static System.Collections.Specialized.BitVector32;

namespace ZeroBug.EasyFlow.Core
{
    [Serializable]
    public class Step
    {
        private FlowBase _flow;
        private IStep? _stepOperator;
        private Step? _parent;
        public string? Description { get; set; }
        public string? Alias { get; set; }
        public string? OperatorName { get; set; }
        public List<Step>? Children { get; set; }
        public SerializableDictionary<string, VariableExpression> Parameters { get; set; }
        public List<VariableJudge> Conditions { get; set; }
        /// <summary>
        /// 运行结果变量
        /// </summary>
        public bool IsRunSuccess { get; set; }
        public bool IsConditionNode { get; set; }
        public string Id { get; set; }
        public bool IsExpanded { get; set; }
        [XmlIgnore]
        public string Tip { get; set; }
        [XmlIgnore]
        public bool Prepare2Run { get; set; }
        [XmlIgnore]
        public Action OnStepPrepare2Run { get; set; }
        [XmlIgnore]
        public Action<DateTime> OnStepStart { get; set; }
        [XmlIgnore]
        public Action<DateTime> OnStepFinish { get; set; }
        [XmlIgnore]
        public Action<DateTime, string> OnStepErr { get; set; }
        [XmlIgnore]
        public Action<bool, string> OnCompileFinish { get; set; }
        [XmlIgnore]
        public Action OnStepBeginNewCycle { get; set; }
        public Step()
        {
            this.Children = new List<Step>();
            this.Parameters = new SerializableDictionary<string, VariableExpression>();
            this.Conditions = new List<VariableJudge>();
            this.Id = Guid.NewGuid().ToString();
        }
        public Step(string description, string operatorName, FlowBase flow) 
            : this()
        {
            this._flow = flow;
            this.Description = description;
            this.OperatorName = operatorName;
        }
        public void SetOperator(IStep? stepOperator)
        {
            this._stepOperator = stepOperator;
        }
        public IStep? GetOperator()
        {
            return _stepOperator;
        }
        public StepResult Run(out string errInfo)
        {
            if (_stepOperator == null)
                throw new ArgumentNullException("step operator is null...");
            OnStepStart?.Invoke(DateTime.Now);
            StepResult result = this._stepOperator.Run(_flow, this, out errInfo);
            OnStepFinish?.Invoke(DateTime.Now);
            if (result == StepResult.Failure)
                OnStepErr?.Invoke(DateTime.Now, errInfo);
            return result;
        }
        public FlowBase GetFlow() => _flow;
        public void SetParent(Step parent)
        {
            _parent = parent;
        }
        public Step GetParent()
        {
            return _parent;
        }
        public Step? GetNext()
        {
            //如果当前步本身指定了下一步，优先用他指定的
            if (this.GetOperator()!.NextStep != null)
                return this.GetOperator()!.NextStep;
            //当前有子步骤，且满足子步执行的条件（该条件来自于当前步本身，由用户根据逻辑决定，如while）则执行子骤的第一步
            else if ((Children != null && Children.Count > 0) && !this.GetOperator()!.IgnoreChildren)
            {
                //这个地方开始运行所有的子步骤
                //可以准备好本作用域的变量
                //如函数步
                _stepOperator!.OnChildrenEnter();
                //正常都是第0个子步开始，但是如果是多条件分支，需要指定进入哪一个分支子步
                return Children[this.GetOperator()!.ChildrenIndex];
            }
            else if (_parent != null)
            {
                //如果父步骤的子步骤还没执行完
                if (_parent.Children!.Count > (_parent.Children!.IndexOf(this) + 1) && !_parent.GetOperator().IsSingleRun)
                    return _parent.Children[_parent.Children!.IndexOf(this) + 1];
                else
                {
                    //这个地方结束了所有的子步，
                    //可以准备好本作用域的返回值
                    //如函数步
                    _parent.GetOperator()?.OnChildrenLeave();
                    //如果父步只能执行一次，比如if之类的，那么要拿到父步的父步，去执行父步的下一步
                    if (_parent.GetOperator().IsSingleRun)
                        return GetParentNext();
                    //if switch的节点 只选取一个节点运行，节点的子步执行完毕后，需执行 if Switch 步的 下一步
                    if (_parent.GetParent()?.GetOperator().IsSingleRun == true)
                        return _parent.GetParent()!.GetParentNext();
                    return _parent;
                }
            }
            else
                return null;
        }
        public Step? GetParentNext()
        {
            if (this.GetParent() != null)
            {
                //如果父步骤是条件步，如if switch，则不能再执行子步了，去父步
                if (_parent.Children!.Count > (_parent.Children!.IndexOf(this) + 1) && !_parent.GetOperator().IsSingleRun)
                    return _parent.Children[_parent.Children!.IndexOf(this) + 1];
                else
                    return this._parent.GetParentNext();
            }
            return null;
        }
        public void InitializeSteps(Dictionary<string, Type> stepOperators, FlowBase flow)
        {
            this.SetOperator(Activator.CreateInstance(stepOperators[this.OperatorName]) as IStep);
            this._flow = flow;
            if (this.Parameters != null)
            {
                foreach (var item in this.Parameters)
                {
                    item.Value.SetVariableManager(this._flow.GetFlowManager().VariableManager);
                }
            }
            foreach (var item in this.Conditions)
            {
                item.SetVariableManager(this._flow.GetFlowManager().VariableManager);
                item.SourceVariable?.SetVariableManager(this._flow.GetFlowManager().VariableManager);
                item.CompareVariable?.SetVariableManager(this._flow.GetFlowManager().VariableManager);
            }
            flow.GetSteps().Add(this);
            if (this.Children != null)
            {
                foreach (var child in this.Children)
                {
                    child.SetParent(this);
                    child.InitializeSteps(stepOperators, flow);
                }
            }
        }
        public void InitializeStep(Dictionary<string, Type> stepOperators, FlowBase flow)
        {
            this.SetOperator(Activator.CreateInstance(stepOperators[this.OperatorName]) as IStep);
            this._flow = flow;
            if(this.Parameters != null)
            {
                foreach (var item in this.Parameters)
                {
                    item.Value.SetVariableManager(this._flow.GetFlowManager().VariableManager);
                }
            }
            if (this.Conditions != null)
            {
                foreach (var item in this.Conditions)
                {
                    item.SetVariableManager(this._flow.GetFlowManager().VariableManager);
                    item.SourceVariable?.SetVariableManager(this._flow.GetFlowManager().VariableManager);
                    item.CompareVariable?.SetVariableManager(this._flow.GetFlowManager().VariableManager);
                }
            }
        }
        public void EnumerateSteps(Action<Step> action)
        {
            action.Invoke(this);
            if (this.Children != null)
            {
                foreach (var child in this.Children)
                {
                    child.EnumerateSteps(action);
                }
            }
        }
        public bool Compile(out string errInfo)
        {
            if (!this._stepOperator.Compile(_flow, this, out errInfo))
            {
                OnCompileFinish(false, errInfo);
                return false;
            }
            OnCompileFinish(true, string.Empty);
            if (this.Children != null)
            {
                foreach (var child in this.Children)
                {
                    if (!child.Compile(out errInfo))
                        return false;
                }
            }
            return true;
        }
        public bool Prepare(out string errInfo)
        {
            if (!this._stepOperator.Prepare(_flow, this, out errInfo))
                return false;
            if (this.Children != null)
            {
                foreach (var child in this.Children)
                {
                    return child.Prepare(out errInfo);
                }
            }
            return true;
        }
        public void RegisterVariables()
        {
            this._stepOperator.RegisterVariables(_flow, this);
            //#region 注册流程步的固有变量
            //Variable conVar = new Variable($"{this.Description}.Result", "false", VariableType.Boolean) { Group = _flow.Description};
            //conVar.GetCurrentValues = () => new string[1] { this.IsRunSuccess.ToString() };
            //_flow.AddVariable(conVar);
            //#endregion
            if (this.Children != null)
            {
                foreach (var child in this.Children)
                {
                    child.RegisterVariables();
                }
            }
        }
        public void UnRegisterVariables()
        {
            this._stepOperator.UnRegisterVariables(_flow, this);
            //#region 注册流程步的固有变量
            //Variable conVar = new Variable($"{this.Description}.Result", "false", VariableType.Boolean) { Group = _flow.Description};
            //conVar.GetCurrentValues = () => new string[1] { this.IsRunSuccess.ToString() };
            //_flow.AddVariable(conVar);
            //#endregion
            if (this.Children != null)
            {
                foreach (var child in this.Children)
                {
                    child.UnRegisterVariables();
                }
            }
        }
        public void AddChildren(Step child)
        {
            this.Children.Add(child);
            child.SetParent(this);
        }
        public void InsertChildren(Step child, int insertIndex)
        {
            this.Children.Insert(insertIndex, child);
            child.SetParent(this);
        }
        public bool CheckParameters(out string errInfo, params string[] parameterNames)
        {
            errInfo = "";
            for (int i = 0; i < parameterNames.Length; i++)
            {
                if (!this.Parameters.ContainsKey(parameterNames[i]))
                {
                    errInfo = $"不存在{parameterNames[i]}变量";
                    return false;
                }
                if (this.Parameters[parameterNames[i]].IsEmpty())
                {
                    errInfo = $"{parameterNames[i]}变量为空";
                    return false;
                }
            }
            return true;
        }

        public void NewCycle()
        {
            OnStepBeginNewCycle?.Invoke();
        }
    }
    public enum StepResult
    {
        Success,
        Failure,
        Break,
    }
    public enum StepGroup
    {
        Control,
        Motion,
        Communication,
        File,
        User,
        Signal,
        UI,
        Variable,
    }
}
